#pragma once
#include <string>

// for compiler g++ using __PRETTY_FUNCTION

template <class T>
std::string get_type_name()
{
  std::string s = __PRETTY_FUNCTION__;
  auto start = s.find("T = ");
  start += 4;
  auto end = s.find_first_of(";]", start);
  return s.substr(start, end - start);
}

template <class E, E V>
std::string get_enum_name()
{
  std::string s = __PRETTY_FUNCTION__;
  auto start = s.find("V = ");
  start += 4;
  auto end = s.find_first_of(";]", start);
  s = s.substr(start, end - start);
  auto pos3 = s.find("::");
  if (pos3 != s.npos)
    s = s.substr(pos3 + 2);
  return s;
}

// template <int V>
// struct int_constant
// {
//   static constexpr int value = V;
// };

// template <int Beg, int End, class F>
// void static_for(F const &func)
// {
//   if constexpr (Beg == End)
//   {
//     return;
//   }
//   else
//   {
//     func(int_constant<Beg>());
//     static_for<Beg + 1, End>(func);
//   }
// }

template <bool Condition>
struct my_enable_if
{
};
template <>
struct my_enable_if<true>
{
  typedef int type;
};

template <int Beg, int End, class F, typename my_enable_if<Beg == End>::type = 0>
void static_for(F const &func)
{
}

template <int Beg, int End, class F, typename my_enable_if<Beg != End>::type = 0>
void static_for(F const &func)
{
  struct int_constant
  {
    enum
    {
      value = Beg
    };
  };

  if constexpr (Beg == End)
  {
    return;
  }
  else
  {
    func(int_constant());
    static_for<Beg + 1, End>(func);
  }
}

template <class E, int Beg = 0, int End = 256>
std::string get_enum_name_dynamic(E v)
{
  std::string ret;
  static_for<Beg, End>([&](auto ic)
                       {
      constexpr auto i = ic.value;
      if (v == (E)i)
        ret = get_enum_name<E, (E)i>(); });
  return ret;
}

template <class E, int Beg = 0, int End = 256>
E enum_from_name(std::string const &s)
{
  for (int i = Beg; i < End; i++)
  {
    if (s == get_enum_name_dynamic((E)i))
    {
      return E(i);
    }
  }
  throw std::runtime_error("not found");
}
